package EP.MetricasContenido;

import SBD.CRUD.JaccardBD;
import Controladores.ControladorOperaciones;
import EP.Web.Pagina;
import EP.Web.RelacionPaginas;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
* @class Jaccard
* @author Mauricio Alvarez.
* @brief Esta clase representa la clase Jaccard, correspondiente a una entidad principal (EP).
*/
public class Jaccard {

    /**
     *  @var int id_pagina
     *  @brief identificador de la página en la BD.
    */
    private int id_pagina;
    /**
     *  @var private int id_relacion_pag
     *  @brief identificador de la página en la BD.
    */
    private int id_relacion_pag;
    /**
     *  @var private String URL
     *  @brief URL de la página evaluada.
    */
    private String URL;
    /**
     *  @var private String Pag
     *  @brief Contenido completo de la página (palabras).
    */
    private String Pag;
    /**
     *  @var private String SText
     *  @brief Contenido de la página (palabras) del texto alrededor.
    */
    private String SText;
    /**
     *  @var private double AYB
     *  @brief Valor en cantidad de elementos resultantes de la intersección de dos conjuntos A y B en Jaccard.
    */
    private double AYB;
    /**
     *  @var private double AUB
     *  @brief Valor en cantidad de elementos resultantes de la unión de dos conjuntos A y B en Jaccard.
    */
    private double AUB;
    /**
     *  @var private double CoeficienteJaccard
     *  @brief Valor del coeficiente de la similitud Jaccard.
    */
    private double CoeficienteJaccard;
    /**
     *  @var private double DistanciaJaccard
     *  @brief Valor de la distancia Jaccard.
    */
    private double DistanciaJaccard;
    /**
     *  @var private ControladorOperaciones cop
     *  @brief Variable global de tipo clase ControladorOperaciones.
    */
    private ControladorOperaciones cop;
    /**
     *  @var private JaccardBD jaccardbd
     *  @brief Variable global de tipo clase JaccardBD.
    */
    private JaccardBD jaccardbd;

    ////////////////////
    // CONSTRUCTOR
    ////////////////////
    public Jaccard()
    {
        cop = new ControladorOperaciones();
        jaccardbd = new JaccardBD();
    }


    ////////////////////////
    // GETTER & SETTER
    ////////////////////////

    public double getCoeficienteJaccard() {
        return CoeficienteJaccard;
    }

    public void setCoeficienteJaccard(double CoeficienteJaccard) {
        this.CoeficienteJaccard = CoeficienteJaccard;
    }

    public double getDistanciaJaccard() {
        return DistanciaJaccard;
    }

    public void setDistanciaJaccard(double DistanciaJaccard) {
        this.DistanciaJaccard = DistanciaJaccard;
    }

    public int getId_pagina() {
        return id_pagina;
    }

    public void setId_pagina(int id_pagina) {
        this.id_pagina = id_pagina;
    }

    public String getUrl() {
        return URL;
    }

    public void setUrl(String URL) {
        this.URL = URL;
    }

    public int getId_relacion_pag() {
        return id_relacion_pag;
    }

    public void setId_relacion_pag(int id_relacion_pag) {
        this.id_relacion_pag = id_relacion_pag;
    }

    public String getSText() {
        return SText;
    }

    public void setSText(String SText) {
        this.SText = SText;
    }


    ////////////////////
    // OPERACIONES
    ////////////////////

    /**
     * @brief Calcula Jaccard no binario según contenido.
     * @param Topico, ListaPaginas, ListaRelacionPaginas, Stopwords, TopicoConsultado, OpcionContenido, Umbral, Ranking
     * @return void
    */
    public void CalcularJaccard(Map<String, Integer> Topico,
                                List<Pagina> ListaPaginas,
                                List<RelacionPaginas> ListaRelacionPaginas,
                                Map<String, Integer> Stopwords,
                                String TopicoConsultado,
                                int OpcionContenido,
                                double Umbral,
                                int Ranking) throws FileNotFoundException, IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, SQLException
    {

        ////////////////////////////////////////////////////////////////////////
        //PASO 0: Segun la selección de OpcionContenido (1:BODY/2:SURROUND TEXT)
        //        se calcula el tf:
        ////////////////////////////////////////////////////////////////////////

        int id_pagina_destino;      //id página destino
        int id_relacion_pag;        //id relacion pagina
        String Texto_alrededor;
        String Header;
        String Title;
        String Anchor_Text;
        String URL;
        String Pag;
        double AYB;
        double AUB;      
        double CJaccard_TA;     //Coeficiente Jaccard del Texto alrededor.
        double DJaccard_TA;     //Distancia Jaccard del Texto alrededor.
        double CJaccard_H;     //Coeficiente Jaccard del Header.
        double DJaccard_H;     //Distancia Jaccard del Header.
        double CJaccard_T;     //Coeficiente Jaccard del Texto alrededor.
        double DJaccard_T;     //Distancia Jaccard del Texto alrededor.
        double CJaccard_AT;     //Coeficiente Jaccard del Texto alrededor.
        double DJaccard_AT;     //Distancia Jaccard del Texto alrededor.
        
        double CoeficienteJaccard; //Coeficiente Jaccard del predictor.
        double DistanciaJaccard;   //Distancia Jaccard del predictor.
        

        ////////////
        // BODY   //
        ////////////
        if (OpcionContenido == 1)
        {
            System.out.println("***************************************");
            System.out.println("**     CALCULO DE JACCARD (BODY)     **");
            System.out.println("***************************************");

            List<String> BOWPaginaLista = new ArrayList();
            Map<String,Integer> BOWPagina = new HashMap();
            Map<String,Integer> BOWTopico = new HashMap();

            Set<String> Diccionario = new HashSet();
            Map<Integer,Jaccard> ResultadosJaccard = new HashMap();

            AYB = 0;
            AUB = 0;
            ////////////////////////////////////////////////////////////////////////
            //PASO 1: Se Calculan las uniones e intersecciones de palabras entre el
            //        BoW de la Página y la Ontología para el coef. Jaccard
            ////////////////////////////////////////////////////////////////////////

            //CONJUNTO B: Tópico.
            //Se genera el BoW del tópico SIN los STOPWORDS:
            BOWTopico = cop.ObtenerPalabrasTopico(Topico, Stopwords); 


            for (int i = 0; i < ListaPaginas.size(); i++) {

                id_pagina = ListaPaginas.get(i).getId_pagina();
                URL = ListaPaginas.get(i).getUrl();
                Pag = ListaPaginas.get(i).getContenido();

                //CONJUNTO B: Palabras de la página
                //Se obtiene BoW del contenido de la pagina i SIN los STOPWORDS:
                if (Pag == null)
                {
                    Pag = "null";
                }

                BOWPaginaLista = cop.ObtenerPalabrasPagina(Pag, Stopwords);

                if (BOWPaginaLista.isEmpty() == true)
                {
                    BOWPaginaLista.add("null");
                }

                for (Iterator<String> iter = BOWPaginaLista.iterator(); iter.hasNext();)
                {
                    BOWPagina.put(iter.next().toString(), 0);
                }

                //Se itera por cada palabra de la página:

                Set set = BOWTopico.entrySet();
                Iterator iter = set.iterator();

                /////////////////////////////////////////
                //PASO 2: Se calcula COEFICIENTE JACCARD
                /////////////////////////////////////////
                //Formula:    Sij = |A Y B| / |A U B|
                //donde:
                // |A Y B| = Intersección de elementos entre conjunto A y B.
                // |A U B| = Unión de elementos de conjuntos A y B.

                while(iter.hasNext()){
                    Map.Entry me = (Map.Entry)iter.next();

                    //Si una palabra de la ontología está en la página:
                    if (BOWPagina.containsKey(me.getKey().toString())== true)
                    {
                        System.out.println("Palabra intersectada para pagina "+ id_pagina + ": "+ me.getKey().toString());
                        AYB++;
                    }
                }

                //Se completa la cantidad de palabras de la Union:
                Diccionario = cop.GenerarDiccionario(BOWTopico, BOWPagina);
                AUB = Diccionario.size();

                //Se calcula el Coeficiente de Jaccard (Smilitud) para la página i:
                CoeficienteJaccard = AYB/Math.sqrt(AUB);

                //Se calcula la distancia Jaccard (Disimilitud)para la página i:
                DistanciaJaccard = 1 - CoeficienteJaccard;

                System.out.println("***************************************");
                System.out.println(i+". id_pagina: "+ id_pagina);
                System.out.println(i+". URL: "+ URL);
                System.out.println(i+". AYB: "+ AYB);
                System.out.println(i+". AUB: "+ AUB);
                System.out.println(i+". Coeficiente Jaccard: "+ CoeficienteJaccard);
                System.out.println(i+". Distancia Jaccard: "+ DistanciaJaccard);
                System.out.println("***************************************");

                AYB = 0;
                AUB = 0;

                //Se guarda el resultado en la estructura de clase:
                Jaccard jaccard = new Jaccard();
                jaccard.setId_pagina(id_pagina);
                jaccard.setUrl(URL);
                jaccard.setCoeficienteJaccard(CoeficienteJaccard);
                jaccard.setDistanciaJaccard(DistanciaJaccard);

                ResultadosJaccard.put(id_pagina, jaccard);

            }

            //////////////////////////////
            //PASO 3: Se guarda en la BD
            //////////////////////////////
            jaccardbd.GuardarMedicionJaccard(ResultadosJaccard, TopicoConsultado, Umbral, Ranking, OpcionContenido);
            jaccardbd.RankearMedicionJaccard(Ranking, TopicoConsultado, OpcionContenido);

        }//FIN IF BODY


        ////////////////////
        // SURROUND TEXT  //
        ////////////////////

        if (OpcionContenido == 2)
        {

            System.out.println("********************************************");
            System.out.println("**     CALCULO DE JACCARD (PREDICTOR)     **");
            System.out.println("********************************************");

            List<String> BOW_AT_Lista = new ArrayList();
            List<String> BOW_TA_Lista = new ArrayList();
            List<String> BOW_H_Lista = new ArrayList();
            List<String> BOW_T_Lista = new ArrayList();
            
            Map<String,Integer> BOW_AT = new HashMap();
            Map<String,Integer> BOW_TA = new HashMap();
            Map<String,Integer> BOW_H = new HashMap();
            Map<String,Integer> BOW_T = new HashMap();
            
            Map<String,Integer> BOWTopico = new HashMap();

            Set<String> Diccionario = new HashSet();
            Map<Integer,Jaccard> ResultadosJaccard = new HashMap<Integer,Jaccard>();

            AYB = 0;
            AUB = 0;

            ////////////////////////////////////////////////////////////////////////
            //PASO 1: Se Calculan las uniones e intersecciones de palabras entre el
            //        BoW del ST y la Ontología para el coef. Jaccard
            ////////////////////////////////////////////////////////////////////////

            //CONJUNTO A: Tópico.
            //Se genera el BoW del tópico SIN los STOPWORDS:
            BOWTopico = cop.ObtenerPalabrasTopico(Topico, Stopwords);

            //Se recorre los ST de los sitios evaluados:
            for (int i = 0; i < ListaRelacionPaginas.size(); i++) 
            {

                AYB = 0;
                AUB = 0;

                //Se setean las variables que se utilizarán:
                id_relacion_pag = ListaRelacionPaginas.get(i).getId_relacion_pagina();
                id_pagina_destino = ListaRelacionPaginas.get(i).getId_pagina_destino();
                Anchor_Text = ListaRelacionPaginas.get(i).getAnchor_text();
                Texto_alrededor = ListaRelacionPaginas.get(i).getTexto_alrededor();
                Header = ListaRelacionPaginas.get(i).getHeader();
                Title = ListaRelacionPaginas.get(i).getTitle();
                
                
                //CONJUNTO B: Palabras del ST.
                //Se pregunta si alguno de los textos que se usarán para el cálculo están vacíos:
                if (Anchor_Text == null )
                    Anchor_Text = "null";
                
                if (Texto_alrededor == null )
                    Texto_alrededor = "null";
                
                if (Header == null )
                    Header = "null";

                if (Title == null )
                    Title = "null";
                
                ////////////////////////////////////////////////////////////////
                //1. PARA ANCHOR TEXT:              
                ////////////////////////////////////////////////////////////////
                BOW_AT_Lista = cop.ObtenerPalabrasPagina(Anchor_Text, Stopwords);

                if (BOW_AT_Lista.isEmpty() == true)
                    BOW_AT_Lista.add("null");

                //Se completa el Map de terminos ST:
                for (Iterator<String> iter1 = BOW_AT_Lista.iterator(); iter1.hasNext();)
                {
                    BOW_AT.put(iter1.next().toString(), 0);
                }

                //Se itera por cada palabra del ST:
                Set set = BOWTopico.entrySet();
                Iterator iter = set.iterator();

                /////////////////////////////////////////
                //PASO 2: Se calcula COEFICIENTE JACCARD
                /////////////////////////////////////////
                //Formula:    Sij = |A Y B| / |A U B|
                //donde:
                // |A Y B| = Intersección de elementos entre conjunto A y B.
                // |A U B| = Unión de elementos de conjuntos A y B.

                while(iter.hasNext())
                {
                    Map.Entry me = (Map.Entry)iter.next();

                    //Si una palabra de la ontología está en el ST:
                    if (BOW_AT.containsKey(me.getKey().toString())== true)
                    {
                        System.out.println("Palabra intersectada para ST "+ id_relacion_pag + ": "+ me.getKey().toString());
                        AYB++;
                    }
                }

                //Se completa la cantidad de palabras de la Union:
                Diccionario = cop.GenerarDiccionario(BOWTopico, BOW_AT);
                AUB = Diccionario.size();

                //Se calcula el Coeficiente de Jaccard (Smilitud) para la página i:
                CJaccard_AT = AYB/AUB;

                //Se calcula la distancia Jaccard (Disimilitud)para la página i:
                DJaccard_AT = 1 - CJaccard_AT;

                System.out.println("***************** ANCHOR TEXT **********************");
                System.out.println(i+". id_relacion_pagina: "+ id_relacion_pag);
                System.out.println(i+". AYB: "+ AYB);
                System.out.println(i+". AUB: "+ AUB);
                System.out.println(i+". Coeficiente Jaccard: "+ CJaccard_AT);
                System.out.println(i+". Distancia Jaccard: "+ DJaccard_AT);
                System.out.println("***************************************");

                AYB = 0;
                AUB = 0;

                ////////////////////////////////////////////////////////////////
                //2. PARA TEXTO ALREDEDOR:
                ////////////////////////////////////////////////////////////////
                BOW_TA_Lista = cop.ObtenerPalabrasPagina(Texto_alrededor, Stopwords);

                if (BOW_TA_Lista.isEmpty() == true)
                    BOW_TA_Lista.add("null");

                //Se completa el Map de terminos ST:
                for (Iterator<String> iter2 = BOW_TA_Lista.iterator(); iter2.hasNext();)
                {
                    BOW_TA.put(iter2.next().toString(), 0);
                }

                //Se itera por cada palabra del ST:
                Set set2 = BOWTopico.entrySet();
                Iterator iter2 = set2.iterator();

                /////////////////////////////////////////
                //PASO 2: Se calcula COEFICIENTE JACCARD
                /////////////////////////////////////////
                //Formula:    Sij = |A Y B| / |A U B|
                //donde:
                // |A Y B| = Intersección de elementos entre conjunto A y B.
                // |A U B| = Unión de elementos de conjuntos A y B.

                while(iter2.hasNext())
                {
                    Map.Entry me = (Map.Entry)iter2.next();

                    //Si una palabra de la ontología está en el ST:
                    if (BOW_TA.containsKey(me.getKey().toString())== true)
                    {
                        System.out.println("Palabra intersectada para ST "+ id_relacion_pag + ": "+ me.getKey().toString());
                        AYB++;
                    }
                }

                //Se completa la cantidad de palabras de la Union:
                Diccionario = cop.GenerarDiccionario(BOWTopico, BOW_TA);
                AUB = Diccionario.size();

                //Se calcula el Coeficiente de Jaccard (Smilitud) para la página i:
                CJaccard_TA = AYB/AUB;

                //Se calcula la distancia Jaccard (Disimilitud)para la página i:
                DJaccard_TA = 1 - CJaccard_TA;

                System.out.println("***************** TEXTO ALREDEDOR **********************");
                System.out.println(i+". id_relacion_pagina: "+ id_relacion_pag);
                System.out.println(i+". AYB: "+ AYB);
                System.out.println(i+". AUB: "+ AUB);
                System.out.println(i+". Coeficiente Jaccard: "+ CJaccard_TA);
                System.out.println(i+". Distancia Jaccard: "+ DJaccard_TA);
                System.out.println("***************************************");

                AYB = 0;
                AUB = 0;
                
                ////////////////////////////////////////////////////////////////
                //3. PARA HEADER:
                ////////////////////////////////////////////////////////////////
                BOW_H_Lista = cop.ObtenerPalabrasPagina(Header, Stopwords);

                if (BOW_H_Lista.isEmpty() == true)
                    BOW_H_Lista.add("null");

                //Se completa el Map de terminos ST:
                for (Iterator<String> iter3 = BOW_H_Lista.iterator(); iter3.hasNext();)
                {
                    BOW_H.put(iter3.next().toString(), 0);
                }

                //Se itera por cada palabra del ST:
                Set set3 = BOWTopico.entrySet();
                Iterator iter3 = set3.iterator();

                /////////////////////////////////////////
                //PASO 2: Se calcula COEFICIENTE JACCARD
                /////////////////////////////////////////
                //Formula:    Sij = |A Y B| / |A U B|
                //donde:
                // |A Y B| = Intersección de elementos entre conjunto A y B.
                // |A U B| = Unión de elementos de conjuntos A y B.

                while(iter3.hasNext())
                {
                    Map.Entry me = (Map.Entry)iter3.next();

                    //Si una palabra de la ontología está en el ST:
                    if (BOW_H.containsKey(me.getKey().toString())== true)
                    {
                        System.out.println("Palabra intersectada para ST "+ id_relacion_pag + ": "+ me.getKey().toString());
                        AYB++;
                    }
                }

                //Se completa la cantidad de palabras de la Union:
                Diccionario = cop.GenerarDiccionario(BOWTopico, BOW_H);
                AUB = Diccionario.size();

                //Se calcula el Coeficiente de Jaccard (Smilitud) para la página i:
                CJaccard_H = AYB/AUB;

                //Se calcula la distancia Jaccard (Disimilitud)para la página i:
                DJaccard_H = 1 - CJaccard_H;

                System.out.println("***************** HEADER **********************");
                System.out.println(i+". id_relacion_pagina: "+ id_relacion_pag);
                System.out.println(i+". AYB: "+ AYB);
                System.out.println(i+". AUB: "+ AUB);
                System.out.println(i+". Coeficiente Jaccard: "+ CJaccard_H);
                System.out.println(i+". Distancia Jaccard: "+ DJaccard_H);
                System.out.println("***************************************");

                AYB = 0;
                AUB = 0;
                      
                ////////////////////////////////////////////////////////////////
                //4. PARA TITLE:
                ////////////////////////////////////////////////////////////////
                BOW_T_Lista = cop.ObtenerPalabrasPagina(Title, Stopwords);

                if (BOW_T_Lista.isEmpty() == true)
                    BOW_T_Lista.add("null");

                //Se completa el Map de terminos ST:
                for (Iterator<String> iter4 = BOW_T_Lista.iterator(); iter4.hasNext();)
                {
                    BOW_T.put(iter4.next().toString(), 0);
                }

                //Se itera por cada palabra del ST:
                Set set4 = BOWTopico.entrySet();
                Iterator iter4 = set4.iterator();

                /////////////////////////////////////////
                //PASO 2: Se calcula COEFICIENTE JACCARD
                /////////////////////////////////////////
                //Formula:    Sij = |A Y B| / |A U B|
                //donde:
                // |A Y B| = Intersección de elementos entre conjunto A y B.
                // |A U B| = Unión de elementos de conjuntos A y B.

                while(iter4.hasNext())
                {
                    Map.Entry me = (Map.Entry)iter4.next();

                    //Si una palabra de la ontología está en el ST:
                    if (BOW_T.containsKey(me.getKey().toString())== true)
                    {
                        System.out.println("Palabra intersectada para ST "+ id_relacion_pag + ": "+ me.getKey().toString());
                        AYB++;
                    }
                }

                //Se completa la cantidad de palabras de la Union:
                Diccionario = cop.GenerarDiccionario(BOWTopico, BOW_T);
                AUB = Diccionario.size();

                //Se calcula el Coeficiente de Jaccard (Smilitud) para la página i:
                CJaccard_T = AYB/AUB;

                //Se calcula la distancia Jaccard (Disimilitud)para la página i:
                DJaccard_T = 1 - CJaccard_T;

                System.out.println("***************** TITLE **********************");
                System.out.println(i+". id_relacion_pagina: "+ id_relacion_pag);
                System.out.println(i+". AYB: "+ AYB);
                System.out.println(i+". AUB: "+ AUB);
                System.out.println(i+". Coeficiente Jaccard: "+ CJaccard_T);
                System.out.println(i+". Distancia Jaccard: "+ DJaccard_T);
                System.out.println("***************************************");

                AYB = 0;
                AUB = 0;
                               
                //Se calculan los pjes. globales:
                //AT = 0.4
                //TA = 0.2
                //H = 0.3
                //T = 0.1
                CoeficienteJaccard = 0.4 * CJaccard_AT + 0.2 * CJaccard_TA + 0.3 * CJaccard_H + 0.1 * CJaccard_T;
                DistanciaJaccard = 1 - CoeficienteJaccard;
                
                System.out.println("***************** FINAL **********************");
                System.out.println(i+". id_relacion_pagina: "+ id_relacion_pag);
                System.out.println(i+". Coeficiente Jaccard: "+ CoeficienteJaccard);
                System.out.println(i+". Distancia Jaccard: "+ DistanciaJaccard);
                System.out.println("***************************************");
                
                
                //Se guarda el resultado en la estructura de clase:
                Jaccard jaccard = new Jaccard();
                jaccard.setId_relacion_pag(id_relacion_pag);
                jaccard.setCoeficienteJaccard(CoeficienteJaccard);
                jaccard.setDistanciaJaccard(DistanciaJaccard);

                ResultadosJaccard.put(id_relacion_pag, jaccard);

            }//FIN for ListaRelacionPaginas

            //////////////////////////////
            //PASO 3: Se guarda en la BD
            //////////////////////////////
            jaccardbd.GuardarMedicionJaccard(ResultadosJaccard, TopicoConsultado, Umbral, Ranking, OpcionContenido);
            jaccardbd.RankearMedicionJaccard(Ranking, TopicoConsultado, OpcionContenido);

        }//FIN IF SURROUND TEXT

    }//FIN CalcularJaccard

}//FIN CLASE Jaccard